var $$ = $$ || {};
$$.Math = $$.Math || {};

/**
 * @memberOf $$.Math
 */
$$.Math._ = function() {};

$$.Math.clamp = function(value, from, to) {
	return Math.max(from, Math.min(to, value));
};

/**
 * Returns value from 0 to 1 showing where is "x" between "from" and "to".
 */
$$.Math.clampedRangePart = function(x, from, to) {
	return Math.min(1, Math.max((x - from) / (to - from), 0));
};

/**
 * Gauss error function, approximation.
 * 
 * 0.112 @ x = 0.1
 * 0.521 @ x = 0.5
 * 0.843 @ x = 1.0
 * 0.966 @ x = 1.5
 * 0.995 @ x = 2.0
 * ~1.0  @ x = 5.0
 * 
 * @see http://en.wikipedia.org/wiki/Error_function
 */
$$.Math.erf = function(x) {
	var xx = x * x;
	var a = 0.147 * xx;
	return Math.sqrt(1 - Math.exp(-xx * (4 / Math.PI + a) / (1 + a)));
};

/**
 * Returns 1 - abs(erf(x)).
 * 
 * @see http://en.wikipedia.org/wiki/Error_function
 */
$$.Math.erfca = function(x) {
	var xx = x * x;
	var a = 0.147 * xx;
	return 1 - Math.abs(Math.sqrt(1 - Math.exp(-xx * (4 / Math.PI + a) / (1 + a))));
};

$$.Math.formatThousands = function(n, delimiter) {
	if (typeof delimiter == 'undefined')
		delimiter = ' ';

	var n = '' + n;
	var re = /(\d+)(\d{3})/;
	
	while(re.test(n))
		n = n.replace(re, '$1' + delimiter + '$2');
	
	return n;
};

$$.Math.interpolate = function(t, from, to) {
	return from + t * (to - from);
};

/**
 * Floating-point ranged random.
 */
$$.Math.random = function(from, to) {
	return from + Math.random() * (to - from);
};

$$.Math.randomVector = function(radius) {
	var a = $$.Math.random(0, Math.PI * 2);
	return { x: radius * Math.cos(a), y: radius * Math.sin(a) };
};

/**
 * Returns 1 - sigmoid(abs(x)), raised into power of gamma.
 * 
 * 0.5 @ x = 0.6
 * 0.4 @ x = 0.75
 * 0.3 @ x = 0.9
 * 0.2 @ x = 1.3
 * 0.1 @ x = 2.1
 * 0.01 @ x = 7
 * 0.001 @ x = 22.5
 * 
 * @see http://en.wikipedia.org/wiki/Sigmoid_function
 */
$$.Math.sigmoidBarrier = function(x, gamma) {
	x = Math.abs(x);
	gamma = gamma || 1;
	
	return Math.pow(1 - x / Math.sqrt(1 + x * x), gamma);
};
